package edu.ssdut.revise.models;

import com.github.javaparser.Range;
import com.github.javaparser.ast.Node;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;

import static edu.ssdut.revise.utils.javaParserUtils.getNodeName;

/**
 * Class used to store refactorings and <b>two</b> corresponding nodes
 *
 * @param <T> the type of the node
 */
public class NodePairWithRefactorings<T extends Node> {
    private static final Logger logger = LoggerFactory.getLogger(NodePairWithRefactorings.class);

    List<T> nodes1 = new ArrayList<>(), nodes2 = new ArrayList<>();
    List<RefactoringType> refactoringTypes = new ArrayList<>();

    public NodePairWithRefactorings(List<T> nodes1, List<T> nodes2) {
        this.nodes1 = nodes1;
        this.nodes2 = nodes2;
    }

    public NodePairWithRefactorings() {
    }

    // used for serialization
    public List<RangeAndDisplayName> getNodes1() {
        // return the range and display name of the nodes!
        return nodes1.stream()
                .map(node -> new RangeAndDisplayName(node.getRange().get(), getNodeName(node)))
                .collect(Collectors.toList());
    }

    public void addNode1(T node1) {
        this.nodes1.add(node1);
    }

    public List<RangeAndDisplayName> getNodes2() {
        // return the range and display name of the nodes!
        return nodes2.stream()
                .map(node -> new RangeAndDisplayName(node.getRange().get(), getNodeName(node)))
                .collect(Collectors.toList());
    }

    public void addNode2(T node2) {
        this.nodes2.add(node2);
    }

    public List<RefactoringType> getRefactoringTypes() {
        return refactoringTypes;
    }

    public void setRefactoringTypes(List<RefactoringType> refactoringTypes) {
        this.refactoringTypes = refactoringTypes;
    }

    @Override
    public String toString() {
        if (refactoringTypes.size() == 0) {
            // no refactor
            return "";
        }
        return nodes2String(nodes1) +
                "  ->  " +
                nodes2String(nodes2) +
                "\n" +
                refactoringTypes +
                "\n";
    }

    private String nodes2String(List<T> nodes) {
        StringBuilder builder = new StringBuilder();
        if (nodes.size() != 0) {
            builder.append("[");
            nodes.forEach(node -> {
                builder.append(getNodeName(node));
                builder.append(", ");
            });
            builder.delete(builder.length() - 2, builder.length());
            builder.append("]");
        } else {
            builder.append("null");
        }
        return builder.toString();
    }

    class RangeAndDisplayName {
        private Range range;
        private String displayName;

        public RangeAndDisplayName(Range range, String displayName) {
            this.range = range;
            this.displayName = displayName;
        }

        public Range getRange() {
            return range;
        }

        public String getDisplayName() {
            return displayName;
        }
    }
}
